package com.domainlanguage.time;

import static com.domainlanguage.TimeAndMoneyTypes.DURATION;
import static com.domainlanguage.internal.FieldReaderUtils.readQuantity;
import static com.domainlanguage.internal.FieldReaderUtils.readUnit;
import static org.hibernate.Hibernate.BIG_DECIMAL;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;

/**
 * Hibernate type for TimeRate.
 *
 */
public class TimeRateType extends ImmutableCompositeUserType {

    private static final String[] PROPERTY_NAMES = {"quantity", "unit"};
    private static final Type[] PROPERTY_TYPES = {BIG_DECIMAL, DURATION};

    @Override
    public String[] getPropertyNames() {
        return PROPERTY_NAMES;
    }

    @Override
    public Type[] getPropertyTypes() {
        return PROPERTY_TYPES;
    }

    @Override
    public Object getPropertyValue(final Object component, final int property) throws HibernateException {
        if (component == null) {
            return null;
        }

        final TimeRate timeRate = (TimeRate) component;

        switch (property) {
            case 0:
                return readQuantity(timeRate);
            case 1:
                return readUnit(timeRate);
            default:
                throw new HibernateException("Property index " + property + " is out of bounds. " +
                        "Properties are: " + Arrays.toString(getPropertyNames()));
        }
    }

    @Override
    public Class returnedClass() {
        return TimeRate.class;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
        final BigDecimal quantity = (BigDecimal) BIG_DECIMAL.nullSafeGet(rs, names[0]);
        final Duration unit = (Duration) DURATION.nullSafeGet(rs, names[1]);

        if (quantity == null || unit == null) {
            return null;
        }

        return new TimeRate(quantity.stripTrailingZeros(), unit);
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
        final TimeRate timeRate = (TimeRate) value;
        final BigDecimal quantity = (timeRate == null) ? null : readQuantity(timeRate);
        final Duration unit = (timeRate == null) ? null : readUnit(timeRate);

        BIG_DECIMAL.nullSafeSet(st, quantity, index);
        DURATION.nullSafeSet(st, unit, index + 1);
    }
}
